package cn.demoncat.util.lang;

import cn.demoncat.util.exception.BizRuntimeException;
import cn.demoncat.util.exception.ParamRuntimeException;
import cn.demoncat.util.lang.constant.LongConstant;
import cn.demoncat.util.lang.constant.StringConstant;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 描述：Long工具
 * 
 * 注：Long最长18位（19位的92...）
 *
 * @author 延晓磊
 *
 * @since 2017年7月10日
 */
public final class LongUtil {

	// 64进制(62进制出错率高，所以额外增加 _- 两个字符)
	private static final char[] CHAR64 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-".toCharArray();

	/**
	 * 判断为空或0
	 * 
	 * @param o
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月16日
	 */
	public static boolean isEmpty(Long o) {
		return o == null || o == 0;
	}

	/**
	 * 判断非空或0
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年1月16日
	 */
	public static boolean isNotEmpty(Long o) {
		return !isEmpty(o);
	}

	/**
	 * 判断为空或0时抛异常
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2022年03月25日
	 */
	public static Long checkEmpty(Long o){
		if (isEmpty(o)) {
			throw ParamRuntimeException.NULL;
		}
		return o;
	}
	
	/**
	 * null转0
	 * 
	 * @param o
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static Long toEmpty(Long o) {
		return o == null ? 0 : o;
	}

	/**
	 * 如果o为null，执行 consumer.accept(“”)
	 *
	 * 例：LongUtil.toEmpty(data.getPid(), data::setPid);
	 *
	 * @param o
	 * @param consumer
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static void toEmpty(Long o, Consumer<Long> consumer) {
		if (o == null) {
			consumer.accept(LongConstant.N0);
		}
	}
	
	/**
	 * null/0 转默认值
	 * 
	 * @param o		数据
	 * @param def	默认值
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static Long toDefault(Long o, Long def) {
		return isEmpty(o) ? def : o;
	}

	/**
	 * null/0 转默认值
	 *
	 * @param o		数据
	 * @param def	默认值
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static Long toDefault(Long o, Supplier<Long> def) {
		return isEmpty(o) ? def.get() : o;
	}

	/**
	 * 转换为字符串
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2021年11月23日
	 */
	public static String toString(Long o){
		return o == null ? null : o.toString();
	}

	/**
	 * 转换为字符串
	 *
	 * @param o
	 * @param def
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2021年11月23日
	 */
	public static String toString(Long o, Long def){
		return o == null ? toString(def) : o.toString();
	}

	/**
	 * 转换字符串为Long
	 *
	 * @param num
	 * @param def	默认值
	 * @return 如果字符串为空则返回def，如果字符串非数值则异常
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年1月5日
	 */
	public static Long valueOf(String num, Long def) {
		num = StringUtils.trimToNull(num);
		// 如果为空，返回def
		if (StringUtil.isBlank(num)) {
			return def;
		}
		// 非空转换，格式错误抛异常
		return Long.valueOf(num);
	}

	/**
	 * 转换字符串为Long
	 *
	 * @param num
	 * @return 如果字符串为空则返回null，如果字符串非数值则异常
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年1月5日
	 */
	public static Long valueOf(String num) {
		return valueOf(num, null);
	}

	/**
	 * 转换字符串为Long
	 *
	 * @param num
	 * @return 如果字符串为空则返回0，如果字符串非数值则异常
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年1月5日
	 */
	public static Long valueOfZero(String num) {
		return valueOf(num, 0L);
	}

	/**
	 * 转换Object为Long
	 * 
	 * @param num
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020-9-15
	 */
	public static Long cast(Object num) {
		if (num == null) {
			return null;
		}
		if (num instanceof Long) {
			return (Long)num;
		}
		if (num instanceof Integer) {
			return ((Integer)num).longValue();
		}
		if (num instanceof Number) {
			return ((Number)num).longValue();
		}
		String str = num.toString();
		if (str.matches(RegexpUtil.NumberRex.INTEGER)) {
			return valueOf(num.toString());
		}
		return null;
	}
	
	/**
	 * 转换为Integer
	 *
	 * @param l
	 * @return
	 * 
	 * @author yxl
	 *
	 * @since 2017年1月5日
	 */
	public static Integer toInt(Long l) {
		if (l == null)
			return null;
		return l.intValue();
	}

	/**
	 * 拼接
	 * 
	 * @param ids
	 * @return "id1-id2..."
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年8月10日
	 */
	public static String join(Long ...ids) {
		return StringUtils.join(ids, StringConstant.BAR);
	}
	
	/**
	 * 拼接（36进制）
	 * 
	 * @param ids
	 * @return "id1-id2..."
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年8月10日
	 */
	public static String join36(Long ...ids) {
		String[] strs = new String[ids.length];
		for (int i = 0; i < ids.length; i++) {
			strs[i] = to36(ids[i]);
		}
		return StringUtils.join(strs, StringConstant.BAR);
	}
	
	/**
	 * 拼接（64进制）
	 * 
	 * @param ids
	 * @return "id1-id2..."
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年8月10日
	 */
	public static String join64(Long ...ids) {
		String[] strs = new String[ids.length];
		for (int i = 0; i < ids.length; i++) {
			strs[i] = to64(ids[i]);
		}
		return StringUtils.join(strs, StringConstant.BAR);
	}
	
	/**
	 * 将数字转换为36进制
	 * 
	 * @param num 
	 * @return "0-9A-Z"
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年1月3日
	 */
	public static String to36(Long num) {
		return Long.toString(num, 36).toUpperCase();
	}
	
	/**
	 * 将36进制转换为数字
	 * 
	 * @param str 	"0-9A-Z"
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年1月3日
	 */
	public static Long parse36(String str) {
		return Long.parseLong(str.toLowerCase(), 36);
	}
	
	/**
	 * 将数字转换为64进制
	 * 
	 * @param num
	 * @return "0-9a-zA-Z_-"
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年1月3日
	 */
	public static String to64(Long num) {
		char[] buf = new char[64];
		int charPos = 64;
		int radix = 1 << 6;
		long mask = radix - 1L;
		do {
			buf[--charPos] = CHAR64[(int) (num & mask)];
			num >>>= 6;
		} while (num != 0);
		return new String(buf, charPos, (64 - charPos));
	}

	/**
	 * 将64进制转换为数字
	 * 
	 * @param str 	"0-9a-zA-Z_-"
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年1月3日
	 */
	public static Long parse64(String str) {
		long result = 0;
		for (int i = str.length() - 1; i >= 0; i--) {
			for (int j = 0; j < CHAR64.length; j++) {
				if (str.charAt(i) == CHAR64[j]) {
					result += ((long) j) << 6 * (str.length() - 1 - i);
				}
			}
		}
		return result;
	}

	/**
	 * 判断区间 min <= v <= max
	 * 
	 * @param v
	 * @param min
	 * @param max
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月5日
	 */
	public static boolean isRange(long v, long min, long max) {
		return v >= min && v <= max;
	}

	/**
	 * 限定区间 min <= v <= max
	 *
	 * @param v
	 * @param min
	 * @param max
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年2月5日
	 */
	public static long range(long v, long min, long max) {
		if(v < min){
			return min;
		}else {
			return Math.min(v, max);
		}
	}

	/**
	 * 判断区间 0 <= v <= max
	 * 
	 * @param v
	 * @param max
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月5日
	 */
	public static boolean isRange(long v, long max) {
		return isRange(v, 0, max);
	}

	/**
	 * 获取区间 0 <= v <= max
	 *
	 * @param v
	 * @param max
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年2月5日
	 */
	public static long range(long v, long max) {
		return range(v, 0, max);
	}

	/**
	 * 运算：加 +
	 *
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static long add(long ...vs) {
		if (vs == null) {
			return LongConstant.N0;
		}
		if (vs.length == 1) {
			return vs[0];
		}
		if (vs.length == 2) {
			return vs[0] + vs[1];
		}
		return Arrays.stream(vs).reduce(Long::sum).getAsLong();
	}

	/**
	 * 运算：减 -
	 *
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static long subtract(long ...vs) {
		if (vs == null) {
			return LongConstant.N0;
		}
		if (vs.length == 1) {
			return vs[0];
		}
		if (vs.length == 2) {
			return vs[0] - vs[1];
		}
		return Arrays.stream(vs).reduce((a,b) -> a - b).getAsLong();
	}

	/**
	 * 运算：减 -
	 *
	 * @param vs	运算数
	 *
	 * @return 结果为负时返回0
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static long subtractZero(long ...vs) {
		long num = subtract(vs);
		if (num < 0) {
			return LongConstant.N0;
		}
		return num;
	}

	/**
	 * 运算：减 -
	 *
	 * @param min	最小值，默认0
	 * @param msg	异常消息（结果小于min）
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static long subtract(Long min, String msg, long ...vs) {
		// 计算
		long r = subtract(vs);
		// 比较
		if (min == null) {
			min = LongConstant.N0;
		}
		if (r < min) {
			if (msg == null) {
				msg = "计算结果不能小于" + min;
			}
			throw new BizRuntimeException(msg);
		}
		return r;
	}

	/**
	 * 运算：减 -
	 *
	 * @param msg	异常消息（结果小于0）
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static long subtractZero(String msg, long ...vs) {
		return subtract(LongConstant.N0, msg, vs);
	}

	/**
	 * 运算：乘 *
	 *
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static long multiply(long ...vs) {
		if (vs == null) {
			return LongConstant.N0;
		}
		if (vs.length == 1) {
			return vs[0];
		}
		if (vs.length == 2) {
			return vs[0] * vs[1];
		}
		return Arrays.stream(vs).reduce((a,b) -> a * b).getAsLong();
	}

	/**
	 * 运算：除 /
	 *
	 * @param vs	运算数：2个及以上，除数 == 0 = 被除数（不再抛异常 java.lang.ArithmeticException: / by zero）
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static long divide(long ...vs) {
		return Arrays.stream(vs).reduce((a,b) -> isEmpty(b) ? a : a / b).getAsLong();
	}

}
